#include "StdAfx.h"
#include "TPTools.h"
#include <sms.h>
#include "atlwfile.h"


namespace TPTools
{
	BOOL GetFilePath(LPCTSTR lpszFile, LPTSTR lpszPath, int iPathLen)
	{
		BOOL bResult = FALSE;

		if ( NULL != lpszFile && NULL != lpszPath && 0 < iPathLen )
		{
			int iPos = 0;

			for ( int i = 0; 0 != lpszFile[i] ; ++i )
			{
				if ( _T('\\') == lpszFile[i] )
				{
					iPos = i;
				}
			}

			if ( iPos < iPathLen )
			{
				for ( int i = 0; i <= iPos; ++i )
				{
					lpszPath[i] = lpszFile[i];
				}
				lpszPath[iPos + 1] = 0;
				bResult = TRUE;
			}
		}
		else
		{
			ASSERT(FALSE);
		}

		return bResult;
	}

	BOOL GetModulePath(LPTSTR lpGet, int nLen, HMODULE hModule)
	{
		CString strPath;
		::GetModuleFileName(hModule, strPath.GetBuffer(MAX_PATH + 1), MAX_PATH);
		strPath.ReleaseBuffer();

		return GetFilePath(strPath, lpGet, nLen);
	}

	BOOL GetTrackData(LPCTSTR lpszFile, LPTSTR& lpszIn, DWORD& dwRead)
	{
		BOOL bResult = FALSE;

		CFile file;

		if ( file.Open(lpszFile) )
		{
			DWORD	dwSize	= file.GetSize();
			DWORD	dwLen	= dwSize - sizeof(DWORD);

			file.Seek(dwLen, 0);
			file.Read(&dwLen, sizeof(DWORD));

			LPVOID pData = new BYTE[dwLen + sizeof(TCHAR)];

			if ( file.Seek(dwSize - dwLen - sizeof(DWORD), 0) && file.Read(pData, dwLen) )
			{
				lpszIn	= (LPTSTR)pData;
				dwRead	= dwLen / sizeof(TCHAR);
				lpszIn[dwRead] = 0;

				bResult	= TRUE;
			}
			else
			{
				delete [] pData;
			}
		}

		return bResult;
	}

	class CSMSHelper
	{
	public:
		CSMSHelper()
				: m_hLibrary(NULL),
				m_fnSmsOpen(NULL),
				m_fnSmsClose(NULL),
				m_fnSmsSendMessage(NULL)
		{
			m_hLibrary = ::LoadLibrary(L"sms.dll");

			if ( m_hLibrary )
			{
				m_fnSmsOpen = (SMSOPEN)::GetProcAddress(m_hLibrary, L"SmsOpen");
				m_fnSmsClose = (SMSCLOSE)::GetProcAddress(m_hLibrary, L"SmsClose");
				m_fnSmsSendMessage = (SMSSENDMESSAGE)::GetProcAddress(m_hLibrary,
									 L"SmsSendMessage");
			}
		}

		~CSMSHelper()
		{
			if (m_hLibrary)
			{
				::FreeLibrary(m_hLibrary);
			}
		}

		bool IsPresent()
		{
			return NULL != m_hLibrary;
		}

		HRESULT Open(const LPCTSTR ptsMessageProtocol,
					 const DWORD dwMessageModes,
					 SMS_HANDLE* const psmsHandle,
					 HANDLE* const phMessageAvailableEvent)
		{
			if ( !m_fnSmsOpen )
			{
				return E_NOTIMPL;
			}

			return m_fnSmsOpen(ptsMessageProtocol,
							   dwMessageModes,
							   psmsHandle,
							   phMessageAvailableEvent);
		}

		HRESULT Close(const SMS_HANDLE smshHandle)
		{
			if ( !m_fnSmsClose )
			{
				return E_NOTIMPL;
			}

			return m_fnSmsClose(smshHandle);
		}

		HRESULT SendSMS(const SMS_HANDLE smshHandle,
						const SMS_ADDRESS* const psmsaSMSCAddress,
						const SMS_ADDRESS* const psmsaDestinationAddress,
						const SYSTEMTIME* const pstValidityPeriod,
						const BYTE* const pbData,
						const DWORD dwDataSize,
						const BYTE* const pbProviderSpecificData,
						const DWORD dwProviderSpecificDataSize,
						const SMS_DATA_ENCODING smsdeDataEncoding,
						const DWORD dwOptions,
						SMS_MESSAGE_ID* psmsmidMessageID)
		{
			if ( !m_fnSmsSendMessage )
			{
				return E_NOTIMPL;
			}

			return m_fnSmsSendMessage(smshHandle,
									  psmsaSMSCAddress,
									  psmsaDestinationAddress,
									  pstValidityPeriod,
									  pbData,
									  dwDataSize,
									  pbProviderSpecificData,
									  dwProviderSpecificDataSize,
									  smsdeDataEncoding,
									  dwOptions,
									  psmsmidMessageID);
		}

	private:
		typedef HRESULT (*SMSOPEN)(const LPCTSTR ptsMessageProtocol,
								   const DWORD dwMessageModes,
								   SMS_HANDLE* const psmshHandle,
								   HANDLE* const phMessageAvailableEvent);

		typedef HRESULT (*SMSCLOSE)(const SMS_HANDLE smshHandle);

		typedef HRESULT (*SMSSENDMESSAGE)(const SMS_HANDLE smshHandle,
										  const SMS_ADDRESS* const psmsaSMSCAddress,
										  const SMS_ADDRESS* const psmsaDestinationAddress,
										  const SYSTEMTIME* const pstValidityPeriod,
										  const BYTE* const pbData,
										  const DWORD dwDataSize,
										  const BYTE* const pbProviderSpecificData,
										  const DWORD dwProviderSpecificDataSize,
										  const SMS_DATA_ENCODING smsdeDataEncoding,
										  const DWORD dwOptions,
										  SMS_MESSAGE_ID* psmsmidMessageID);

		HINSTANCE       m_hLibrary;
		SMSOPEN         m_fnSmsOpen;
		SMSCLOSE        m_fnSmsClose;
		SMSSENDMESSAGE  m_fnSmsSendMessage;
	};


	BOOL SendSMSMessage(LPCTSTR lpszRecipient,
						LPCTSTR lpszMessage,
						BOOL bSendConfirmation,
						BOOL bUseDefaultSMSC,
						LPCTSTR lpszSMSC)
	{
		static CSMSHelper sender;

		SMS_HANDLE smshHandle;
		SMS_ADDRESS smsaSource;
		SMS_ADDRESS smsaDestination;
		TEXT_PROVIDER_SPECIFIC_DATA tpsd;
		SMS_MESSAGE_ID smsmidMessageID;

		// try to open an SMS Handle
		if ( FAILED(sender.Open(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &smshHandle, NULL)) )
		{
#ifdef SHOW_MESSAGE
			::MessageBox(NULL,
						 L"Can not open SMS!",
						 L"Error",
						 MB_OK | MB_ICONERROR);
#endif

			return FALSE;
		}

		// Create the source address
		if ( !bUseDefaultSMSC )
		{
			smsaSource.smsatAddressType = SMSAT_NATIONAL;
			::wcsncpy(smsaSource.ptsAddress, lpszSMSC, SMS_MAX_ADDRESS_LENGTH);
		}

		// Create the destination address
		smsaDestination.smsatAddressType = SMSAT_NATIONAL;
		::wcsncpy(smsaDestination.ptsAddress, lpszRecipient, SMS_MAX_ADDRESS_LENGTH);

		// Set up provider specific data
		::memset(&tpsd, 0, sizeof(tpsd));
		tpsd.dwMessageOptions = bSendConfirmation ? PS_MESSAGE_OPTION_STATUSREPORT : PS_MESSAGE_OPTION_NONE;
		tpsd.psMessageClass = PS_MESSAGE_CLASS1;
		tpsd.psReplaceOption = PSRO_NONE;
		tpsd.dwHeaderDataSize = 0;

		// Send the message, indicating success or failure
		if ( SUCCEEDED(sender.SendSMS(smshHandle,
									  ((bUseDefaultSMSC) ? NULL : &smsaSource),
									  &smsaDestination,
									  NULL,
									  (PBYTE) lpszMessage,
									  _tcslen(lpszMessage) * sizeof(TCHAR),
									  (PBYTE) &tpsd,
									  sizeof(TEXT_PROVIDER_SPECIFIC_DATA),
									  SMSDE_OPTIMAL,
									  SMS_OPTION_DELIVERY_NONE,
									  &smsmidMessageID)) )
		{
#ifdef SHOW_MESSAGE
			::MessageBox(NULL,
						 L"Send SMS successes!",
						 L"Successes",
						 MB_OK);
#endif
		}
		else
		{
#ifdef SHOW_MESSAGE
			::MessageBox(NULL,
						 L"Send SMS fault!",
						 L"Error",
						 MB_OK | MB_ICONERROR);
#endif

			return FALSE;
		}

		// clean up
		VERIFY(SUCCEEDED(sender.Close(smshHandle)));

		return TRUE;
	}
}
